
import logging
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import login_required
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
from google.appengine.api import users
from django.utils import simplejson
from google.appengine.api.labs import taskqueue

from models import *

from cgi import escape

def esc(txt):
    txt = txt.replace("'",'"')
    return escape(txt, True)

def loginRequired(func):
    def wrapper(self, *args, **kw):
        user = users.get_current_user()
        if not user:
            logging.debug('Login Required')
            return {'error': 'Login required'}
        else:
            return func(self, *args, **kw)
    return wrapper


def loginProfileRequired(func):
    def wrapper(self, *args, **kw):
        user = users.get_current_user()
        if not user:
            logging.debug('User Required')
            return {'error': 'User required'}
        else:
            kw['profile'] = Profile.all().filter("user =", user).get()
            if not kw['profile']:
                return {'error': 'User Profile required'}
            else:
                return func(self, *args, **kw)
    return wrapper

def nicknameProfileRequired(func):
    def wrapper(self, *args, **kw):
        user = users.get_current_user()
        nickname = kw['nickname']
        kw['nickname'] = None
        if not nickname:
            logging.debug('Nickname Required')
            return {'error': 'Nickname required'}
        else:
            kw['profile'] = Profile.all().filter("nickname =", nickname).get()
            if not kw['profile']:
                return {'error': 'Nickname Profile required'}
            else:
                return func(self, *args, **kw)
    return wrapper


class RPCHandler(webapp.RequestHandler):
    """ Allows the functions defined in the RPCMethods class to be RPCed."""
    def __init__(self):
        webapp.RequestHandler.__init__(self)
        self.methods = RPCMethods()
    #@login_required
    def get(self):
        func = None

        logging.debug(self.request.arguments())
        action = self.request.get('action')
        if action:
            if action[0] == '_':
                self.error(403) # access denied
                return
            else:
                func = getattr(self.methods, action, None)

        if not func:
            self.error(404) # file not found
            return

        args = []
        while True:
            key = 'arg%d' % len(args)
            val = self.request.get(key)
            if val:
                args.append(val)
                #args += (simplejson.loads(val),)
            else:
                break

        kwargs = dict()
        for kw in self.request.arguments():
            if kw != "action":
                kwargs[str(kw)] = str(self.request.get(kw))

        logging.debug(kwargs)
        result = func(**kwargs)
        self.response.out.write(simplejson.dumps(result))


class RPCMethods:
    """ Defines the methods that can be RPCed.
    NOTE: Do not allow remote callers access to private/protected "_*" methods.
    """
    @loginProfileRequired
    def AddMovie(self, name, rating, profile):
        rating = db.Rating(int(rating))
        name = esc(name)
        movie = Movie(name=name, profile=profile, average=rating, votes=1, abuseflags=0)
        movie.put()
        self.RateMovie(movie.key(),rating)
        return {'name' : movie.name}

    @loginProfileRequired
    def AddToMyList(self, movie, profile):
        movie = db.get(movie)

        # delete any previous mustsees I have for this movie
        mustsees = MustSee.all().filter("movie =", movie).filter("profile =", profile)
        for m in mustsees:
            m.delete()

        # delete any previous ratings I might have for this movie (how can you rate it if you havent seen it)
        ratings = Rating.all().filter("movie =", movie).filter("profile =", profile)
        for r in ratings:
            r.delete()

        mustsee = MustSee(profile=profile, movie=movie)
        mustsee.put()
        return {'name' : mustsee.movie.name}

    @loginProfileRequired
    def RateMovie(self, movie, rating, profile):
        movie = db.get(movie)
        myrating = db.Rating(int(rating))

        # delete any previous ratings I might have for this movie
        ratings = Rating.all().filter("movie =", movie).filter("profile =", profile)
        for r in ratings:
            r.delete()

        # delete any mustsees I have for this movie ( its not on the list anymore if I have watched it)
        mustsees = MustSee.all().filter("movie =", movie).filter("profile =", profile)
        for m in mustsees:
            m.delete()

        # create a new rating
        rating = Rating(profile=profile, movie=movie, rating=myrating)
        rating.put()

        taskqueue.add(url='/averageratings', params={'movie': str(movie.key())})
        return {'name':movie.name, 'rating': rating.movie.average }

    def GetMovies(self):
        movies = Movie.all()
        movies.order('-average')
        movielist = []
        for movie in movies:
            movielist.append({
                'name':movie.name,
                'rating':movie.average,
                'votes':movie.votes,
                'key':str(movie.key()),
                'user':movie.profile.nickname or "error",
                })
        return {'movies' : movielist}

    @nicknameProfileRequired
    def GetMoviesIveSeen(self, profile):
        movielist = []
        for rating in profile.ratings:
            movielist.append({
                'name':rating.movie.name,
                'rating':rating.movie.average,
                'votes':rating.movie.votes,
                'key':str(rating.movie.key()),
                })
        return {'movies' : movielist}

    @nicknameProfileRequired
    def GetMoviesIMustSee(self, profile):
        movielist = []
        for mustsee in profile.mustsees:
            movielist.append({
                'name':mustsee.movie.name,
                'rating':mustsee.movie.average,
                'votes':mustsee.movie.votes,
                'key':str(mustsee.movie.key()),
                })
        return {'movies' : movielist}

    @nicknameProfileRequired
    def GetMoviesIAdded(self, profile):
        movielist = []
        for movie in profile.movies.order("-average"):
            movielist.append({
                'name':movie.name,
                'rating':movie.average,
                'votes':movie.votes,
                'key':str(movie.key()),
                })
        return {'movies' : movielist}

    @loginRequired
    def NicknameAvailable(self, nickname):
        profile = Profile.all().filter("nickname =", nickname).get()
        if not profile:
            return {'available' : 1}
        else:
            return {'available' : 0}


